#include "health_api.h"
#include "common.h"
#include "health_impl.h"
#include "vector.h"
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define NEWH()                                                                 \
  hourly_data_t *h = _new_hl(init_ts);                                         \
  smp_hr_t *ts = analyze_hr(hr_list + begin, sub_count, &rate_avg, &num_out);  \
  h->avg_hr = rate_avg;                                                        \
  h->len = num_out;                                                            \
  h->hr_list = ts;                                                             \
  append_item(cache, h, NULL);

/*
ts to struct
@param ts: milliseconds
 */
static void _ts2tm(uint64_t ts, struct tm *result) {
  time_t v = (time_t)(ts / 1000);
  /*
  gmtime store result in statically allocated space
  will overwrited by sub calls

  no gmtime_r defined
   */
#ifdef _WIN32
  struct tm y;
  gmtime_s(&y, &v);
  struct tm *m = &y;
#else
  struct tm *m = gmtime(&v);
#endif
  memcpy(result, m, sizeof(struct tm));
}

/*
小时相同
 */
static uint8_t _same_hour(const struct tm *a, const struct tm *b) {
  if (!a || !b)
    return 0;

  if (a->tm_year != b->tm_year)
    return 0;
  if (a->tm_mon != b->tm_mon)
    return 0;
  if (a->tm_mday != b->tm_mday)
    return 0;

  return a->tm_hour == b->tm_hour;
}

static hourly_data_t *_new_hl(uint64_t ts) {
  hourly_data_t *h = (hourly_data_t *)malloc(sizeof(hourly_data_t));
  if (!h) {
    return NULL;
  }

  h->ts = ts;
  return h;
}

hourly_data_t *run_hourly_data(smp_hr_t *hr_list, size_t len, uint32_t *nh) {
  if (!hr_list || !len) {
    *nh = 0;
    return NULL;
  }

  struct tm tm_a, tm_b;
  uint64_t init_ts;
  size_t sub_count = 0, begin = 0;

  double rate_avg;
  size_t num_out;

  linked_list_t *cache = NULL;
  new_linklist(&cache);

  for (size_t i = 0; i < len; i++) {
    const smp_hr_t *cur = hr_list + i;

    _ts2tm(cur->ts, 0 == sub_count ? &tm_a : &tm_b);
    if (0 == sub_count)
      init_ts = cur->ts;

    if (0 == sub_count) {
      // 索引0跳过，但计数需+
      sub_count = 1;
      continue;
    }

    if (!_same_hour(&tm_a, &tm_b)) {
      NEWH();

      _ts2tm(cur->ts, &tm_a);
      init_ts = cur->ts;
      begin = i;
      sub_count = 1;
      continue;
    }
    sub_count++;
  }

  NEWH();

  hourly_data_t *result =
      (hourly_data_t *)iter_copy(cache, sizeof(hourly_data_t), nh, NULL);
  free_items(cache, NULL, 0, NULL);
  return result;
}

void free_hourly(hourly_data_t *hlist, size_t count) {
  if (!hlist)
    return;

  for (size_t i = 0; i < count; i++) {
    smp_hr_t *slist = (hlist + i)->hr_list;
    if (slist)
      free(slist);
  }
  free(hlist);
}